#include <QVBoxLayout>
#include <QThreadPool>
#include <QLabel>

#include "LibView.h"
#include "ReaderWriter.h"

LibView::LibView(QWidget *parent) : QWidget(parent) {
    setLayout(new QVBoxLayout);

    initComponents();
    initConnections();

    readIntervalSlider->setValue(1000);
    writeIntervalSlider->setValue(1000);
    booksSlider->setValue(5);
    writersSlider->setValue(1);
    readersSlider->setValue(3);
}

void LibView::initComponents() {
    numberOfBooksPB = new QProgressBar();
    readersWritersPB = new  QProgressBar();

    layout()->addWidget(new QLabel("books available:"));
    layout()->addWidget(numberOfBooksPB);
    layout()->addWidget(new QLabel("working:"));
    layout()->addWidget(readersWritersPB);

    booksSlider = new QSlider(Qt::Horizontal);
    booksSlider->setRange(1, MAX_BOOKS);
    readIntervalSlider = new QSlider(Qt::Horizontal);
    readIntervalSlider->setRange(0, MAX_RW_INTERVAL);
    writeIntervalSlider = new QSlider(Qt::Horizontal);
    writeIntervalSlider->setRange(0, MAX_RW_INTERVAL);
    readersSlider = new QSlider(Qt::Horizontal);
    readersSlider->setRange(0, MAX_WORKERS);
    writersSlider = new QSlider(Qt::Horizontal);
    writersSlider->setRange(0, MAX_WORKERS);

    layout()->addWidget(new QLabel("#books:"));
    layout()->addWidget(booksSlider);
    layout()->addWidget(new QLabel("readers:"));
    layout()->addWidget(readersSlider);
    layout()->addWidget(new QLabel("writers:"));
    layout()->addWidget(writersSlider);
    layout()->addWidget(new QLabel("reader interval:"));
    layout()->addWidget(readIntervalSlider);
    layout()->addWidget(new QLabel("writer interval:"));
    layout()->addWidget(writeIntervalSlider);

}

void LibView::initConnections() {
    connect(&library, SIGNAL(numberOfBooksChanged(int)),
            numberOfBooksPB, SLOT(setValue(int)));
    numberOfBooksPB->setFormat("%v/%m");

    connect(&library, SIGNAL(awaitingUpdate(int)),
            this, SLOT(setWaitCount(int)));
    readersWritersPB->setFormat("%v/%m");

    connect(readIntervalSlider, SIGNAL(valueChanged(int)),
            &library, SLOT(setReaderInterval(int)));
    connect(writeIntervalSlider, SIGNAL(valueChanged(int)),
            &library, SLOT(setWriterInterval(int)));
    connect(booksSlider, SIGNAL(valueChanged(int)),
            numberOfBooksPB, SLOT(setMaximum(int)));
    connect(booksSlider, SIGNAL(valueChanged(int)),
            &library, SLOT(updateMaxBooks(int)));
    connect(readersSlider, SIGNAL(valueChanged(int)),
            this, SLOT(updateNumberOfReaders(int)));
    connect(writersSlider, SIGNAL(valueChanged(int)),
            this, SLOT(updateNumberOfWriters(int)));

}

void LibView::setWaitCount(int waitCount) {
    readersWritersPB->setValue(readersWritersPB->maximum() - waitCount);
}

void LibView::updateWorkers(QVector<Worker*> &workers,
                            int newValue,
                            Worker* (*repptr)(Library&)) {
    int delta = newValue - workers.size();

    while (delta > 0) {
        workers.push_back(repptr(library));
        QThreadPool::globalInstance()->start(workers.back());
        --delta;
    }

    while (delta < 0) {
        workers.back()->interrupt();
        workers.pop_back();
        ++delta;
    }

    readersWritersPB->setMaximum(writersVec.size() + readersVec.size());
    QThreadPool::globalInstance()->
            setMaxThreadCount(writersVec.size() + readersVec.size());
}


Worker* replicateReader(Library &lib) { return new Reader(lib); }
Worker* replicateWriter(Library &lib) { return new Writer(lib); }

void LibView::updateNumberOfReaders(int newValue) {
    updateWorkers(readersVec, newValue, replicateReader);
}

void LibView::updateNumberOfWriters(int newValue) {
    updateWorkers(writersVec, newValue, replicateWriter);
}
